<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width">
  </head>
  <body>
    <input id="input_text">
    <input id="input_autocapitalize_none" autocapitalize="none">
    <input id="input_autocapitalize_characters" autocapitalize="characters">
    <input id="input_autocapitalize_words" autocapitalize="words">
    <input id="input_autocapitalize_sentences" autocapitalize="sentences">

    <form autocapitalize="none">
      <input id="input_autocapitalize_inherit_none">
    </form>

    <div id="div_autocapitalize_characters" contenteditable autocapitalize="characters">
    </div>
  </body>

  <script>
    var selectionChangeEventLog = "";
    var otherEventLog = "";
    var mutationObserver = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        addEventLog(mutation.type, mutation.detail);
      });
    })

    var mutationConfig = { attributes: false, childList: false, characterData: true };

    function addOtherEventLog(type, detail) {
      if (otherEventLog.length > 0) {
        otherEventLog += ',';
      }
      if (detail == null) {
        otherEventLog += type;
      } else {
        otherEventLog += type + '(' + detail + ')';
      }
    }

    function addSelectionChangeEventLog(type, detail) {
      if (selectionChangeEventLog.length > 0) {
        selectionChangeEventLog += ',';
      }
      if (detail == null) {
        selectionChangeEventLog += type;
      } else {
        selectionChangeEventLog += type + '(' + detail + ')';
      }
    }

    // selectionchange event is queued, so it races with the other events.
    // crbug.com/628964
    function getEventLogs() {
      if (otherEventLog.length > 0 && selectionChangeEventLog.length > 0)
        return otherEventLog + ',' + selectionChangeEventLog;
      return otherEventLog + selectionChangeEventLog;
    }

    function clearEventLogs() {
      selectionChangeEventLog = '';
      otherEventLog = '';
    }

    function addEventListener(element, event_name) {
      element.addEventListener(event_name, function (e) { addOtherEventLog(event_name, e.data); });
    }

    function addKeyEventListener(element, event_name) {
      element.addEventListener(event_name, function (e) { addOtherEventLog(event_name, e.keyCode); });
    }

    function addSelectionEventListener(event_name) {
      // Note that listeners added to the element are not effective for now.
      document.addEventListener(event_name, function (e) { addSelectionChangeEventLog(event_name, e.data); });
    }

    function registerListenersAndObserver(element) {
      addKeyEventListener(element, "keydown");
      addKeyEventListener(element, "keypress");
      addKeyEventListener(element, "keyup");
      addEventListener(element, "compositionstart");
      addEventListener(element, "compositionupdate");
      addEventListener(element, "compositionend");
      addEventListener(element, "beforeedit");
      addEventListener(element, "edit");
      addEventListener(element, "select");
      addEventListener(element, "change");
      addEventListener(element, "input");
      mutationObserver.observe(element, mutationConfig);
    }

    var inputText = document.getElementById("input_text");
    var contenteditableEvent = document.getElementById("contenteditable_event");

    // SelectionEventListener should be outside registerListenersAndObserver() to avoid duplication.
    addSelectionEventListener("selectionchange");

    registerListenersAndObserver(inputText);
    registerListenersAndObserver(contenteditableEvent);
  </script>
</html>
